@file:Suppress("UNUSED_EXPRESSION")

package han.cirno.corrupt.modules.home

import androidx.activity.compose.LocalActivity
import androidx.appcompat.app.AppCompatActivity
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.FlowRow
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.Button
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.LinearProgressIndicator
import androidx.compose.material3.Text
import androidx.compose.material3.pulltorefresh.PullToRefreshBox
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.runtime.mutableLongStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel
import han.cirno.corrupt.R
import han.cirno.corrupt.activity.GlobalViewModel
import han.cirno.corrupt.activity.main.FunctionSelector
import han.cirno.corrupt.activity.main.LocalBottomPadding
import han.cirno.corrupt.activity.main.LocalNavController
import han.cirno.corrupt.activity.main.MainActivityViewModel
import han.cirno.corrupt.activity.main.NavItem
import han.cirno.corrupt.activity.main.navigate
import han.cirno.corrupt.components.calendar.ClassesTimeLine
import han.cirno.corrupt.components.update.ApkUpdateHelper
import han.cirno.corrupt.compose.QuickCard
import han.cirno.corrupt.compose.QuickOutlinedCard
import han.cirno.corrupt.compose.TitleTextWithIcon
import han.cirno.corrupt.compose.VerticalSpacer
import han.cirno.corrupt.compose.localeStringResource
import han.cirno.corrupt.data.instances.UserExamData
import han.cirno.corrupt.modules.exam.SingleExamCard
import kotlinx.coroutines.delay
import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch
import java.io.File
import java.util.Calendar

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun HomeLayout(){
    val mainActivityViewModel:MainActivityViewModel= hiltViewModel(LocalActivity.current as AppCompatActivity)
    val globalViewModel: GlobalViewModel = hiltViewModel()
    val nofyEnabled by globalViewModel.broadcastCheck.observeAsState()
    val isLogged by mainActivityViewModel.isLoggedState.collectAsState()
    val updateAvailable by mainActivityViewModel.updateAvailableState
    val scope = rememberCoroutineScope()
    var currentTime by remember { mutableLongStateOf(System.currentTimeMillis()) }

    DisposableEffect(Unit) {
        val job = scope.launch {
            while (isActive) {
                currentTime = System.currentTimeMillis()
                delay(1000L)
            }
        }
        onDispose {
            job.cancel()
        }
    }
    PullToRefreshBox (
        isRefreshing = false,
        onRefresh = {
            mainActivityViewModel.refresh()
        },
        indicator = { }
    ) {
        Column(
            modifier = Modifier
                .padding(horizontal = 16.dp)
                .verticalScroll(rememberScrollState())
        ) {
            VerticalSpacer(8.dp)
            CardInfo()
            AnimatedVisibility(visible = nofyEnabled == 1) { CardNofy() }
            AnimatedVisibility(visible = !isLogged) { CardLoginHint() }
            AnimatedVisibility(visible = updateAvailable) { CardUpdate(mainActivityViewModel) }
            AnimatedVisibility(visible = isLogged) {
                CardClasses(
                    currentTime
                )
            }
            AnimatedVisibility(visible = isLogged) { CardExams(currentTime, mainActivityViewModel) }
            CardFunctions()
            VerticalSpacer(8.dp)
            VerticalSpacer(LocalBottomPadding.current)
        }
    }
}

@Composable
fun CardExams(currentTime: Long, mainActivityViewModel: MainActivityViewModel)=
    QuickCard {
        val exams by mainActivityViewModel.allExamsFlow.collectAsState()
        val nowTime=System.currentTimeMillis()
        TitleTextWithIcon(
            iconRes = R.drawable.baseline_school_24,
            textRes = R.string.card_exams_title,
        )
        Column {
            VerticalSpacer(8.dp)
            exams
                .filter { it.getTimeDelta(nowTime).timeState.let {e->
                    e!=UserExamData.Exam.TimeState.Unspecified&&
                    e!=UserExamData.Exam.TimeState.End
                } }
                .forEach { exam -> SingleExamCard(currentTime, exam) }
        }
    }

@Composable
fun CardClasses(currentTime: Long) =
    QuickCard {
        TitleTextWithIcon(
            iconRes = R.drawable.baseline_class_24,
            textRes = R.string.card_classesInfo_title
        )
        val (mainText, subText, progress) = getClassesUIInfo()
        Column {
            currentTime
            VerticalSpacer(8.dp)
            AnimatedVisibility(visible = mainText != null) {
                if (mainText == null) return@AnimatedVisibility;Text(
                text = mainText
            )
            }
            AnimatedVisibility(visible = subText != null) {
                if (subText == null) return@AnimatedVisibility;Text(text = subText)
            }
            AnimatedVisibility(visible = progress != null) {
                Column {
                    if (progress == null) return@AnimatedVisibility
                    VerticalSpacer(4.dp)
                    LinearProgressIndicator(
                        modifier = Modifier.fillMaxWidth(),
                        progress = { progress })
                }
            }
        }
    }

@Composable
fun CardFunctions()= QuickCard {
    val mainActivityViewModel:MainActivityViewModel= hiltViewModel(LocalActivity.current as AppCompatActivity)
    val trigger by mainActivityViewModel.functionsRefreshTrigger
    val functions = remember(trigger) { FunctionSelector.functionTable.filter { it.showPredicate() }}
    TitleTextWithIcon(
        iconRes = R.drawable.baseline_functions_24,
        textRes = R.string.card_functions_title
    )
    VerticalSpacer(8.dp)
    FlowRow(
        maxItemsInEachRow = 3,
        modifier = Modifier.fillMaxSize()
    ) {
        functions.forEach { function ->
            Box(modifier = Modifier.weight(1f)) {
                FunctionCard(function)
            }
        }
    }
}

@Composable
fun CardInfo()= QuickCard {
    TitleTextWithIcon(
        iconRes = R.drawable.baseline_account_circle_24,
        textRes = R.string.card_personalInfo_title
    )
}

@Composable
fun CardNofy()= QuickCard {
    TitleTextWithIcon(
        iconRes = R.drawable.baseline_brightness_5_24,
        textRes = R.string.card_nofy_title
    )
    VerticalSpacer(8.dp)
    Text(localeStringResource(R.string.card_nofy_content))
}

@Composable
fun CardLoginHint()= QuickCard {
    val navController=LocalNavController.current
    TitleTextWithIcon(
        iconRes = R.drawable.baseline_login_24,
        textRes = R.string.card_loginRequire_title
    )
    VerticalSpacer(8.dp)
    Button(onClick = {
        navController.navigate(NavItem.LoginScreen)
    }) { Text(localeStringResource(R.string.card_loginRequire_button)) }
}

@Composable
fun CardUpdate(mainActivityViewModel: MainActivityViewModel)= QuickCard{
    TitleTextWithIcon(
        iconRes = R.drawable.baseline_system_update_24,
        textRes = R.string.card_update_title
    )
    VerticalSpacer(8.dp)
    val updateStatus by mainActivityViewModel.updateStatusState
    AnimatedVisibility(visible = updateStatus==0) {
        val updateVersion by mainActivityViewModel.updateVersionState
        val updateSize by mainActivityViewModel.updateSizeState
        val currentVersion=LocalContext.current.let{it.packageManager.getPackageInfo(it.packageName,0).versionName}
        Column {
            Text(text = localeStringResource(
                R.string.card_update_available,
                currentVersion.toString(),
                updateVersion
            ))
            Button(
                modifier = Modifier.fillMaxWidth(),
                onClick = { mainActivityViewModel.performUpdate() }) {
                Text(text = localeStringResource(R.string.card_update_update, updateSize))
            }
        }
    }
    AnimatedVisibility(visible = updateStatus==1) {
        val updateProgress by mainActivityViewModel.updateProgressState
        val pair:Pair<Int,Int>?=if (updateProgress.isEmpty()){
            null
        }else{
            val progressSplit = updateProgress.split(';')
            val progress=progressSplit[0].toInt()
            val total=progressSplit[1].toInt()
            progress to total
        }
        Column (modifier = Modifier.fillMaxWidth()) {
            val noStatus=pair==null||pair.first==-1
            Text(
                modifier = Modifier.fillMaxWidth(),
                textAlign = TextAlign.End,
                text=
                    if (noStatus) localeStringResource(R.string.card_update_pending)
                    else "${"%.1f".format(pair!!.first/1024f/1024f)}/${"%.1f".format(pair.second/1024f/1024f)}MB")
            if(noStatus)LinearProgressIndicator(modifier = Modifier.fillMaxWidth())
            else LinearProgressIndicator(
                modifier = Modifier.fillMaxWidth(),
                progress = {pair!!.first/ pair.second.toFloat()})
        }
    }
    AnimatedVisibility(visible = updateStatus==2) {
        val context =LocalContext.current
        Button(
            modifier = Modifier.fillMaxWidth(),
            onClick = { ApkUpdateHelper.installApk(context, File(context.cacheDir,"latest.apk"))
        }) {
            Text(text = localeStringResource(R.string.card_update_install))
        }
    }
}

@Composable
private fun getClassesUIInfo():Triple<String?,String?,Float?>{
    val timeLine = ClassesTimeLine.fromTable()
    val calendar=Calendar.getInstance()
    val nowSecond=calendar[Calendar.HOUR_OF_DAY]*60*60+calendar[Calendar.MINUTE]*60+calendar[Calendar.SECOND]
    val (classEntry, timeLeft, timeTotal, isInClass, phase, totalPhase) = timeLine.getCurrentState(
        nowSecond)?:return Triple(null,null,0f)
    val hour = timeLeft / (60 * 60)
    val min = timeLeft / 60 - (hour * 60)
    val second = timeLeft - (min * 60) - (hour * 60 * 60)
    if (isInClass) {
        return Triple(
            localeStringResource(
                R.string.card_classesInfo_inClass,
                classEntry!!.name,
                classEntry.place,
                phase + 1,
                totalPhase),
            localeStringResource(
                R.string.card_classesInfo_sub_endAt,
                hour, min, second
            ),
            timeLeft.toFloat()/timeTotal.toInt()
        )
    }
    if (classEntry != null) {
        return Triple(
            localeStringResource(
                R.string.card_classesInfo_break,
                classEntry.name,
                classEntry.place),
            localeStringResource(
                R.string.card_classesInfo_sub_startAt,
                hour, min, second),
            (timeTotal - timeLeft)/timeTotal.toFloat()
        )
    }
    return Triple(localeStringResource(R.string.card_classesInfo_end_1),null,null)
}

@Composable
private fun FunctionCard(function: FunctionSelector.Function) {
    val navController= LocalNavController.current
    QuickOutlinedCard(
        modifier = Modifier.fillMaxWidth(),
        onClick = { function.navJump?.invoke(navController) }) {
        Column(
            modifier = Modifier.fillMaxSize(),
            horizontalAlignment = Alignment.CenterHorizontally,
            verticalArrangement = Arrangement.Center
        ) {
            Icon(painter = painterResource(function.iconRes), null)
            Text(text = localeStringResource(function.nameRes))
        }
    }
}